#pragma once
#include "Common.hpp"
#include "Channel.hpp"

#define MAX_EPOLLEREVENTS 1024
class Poller{
private:
    // 对 epoll 的之间操作
    void Update(Channel* channel, int op){
        // int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
        int fd = channel->Fd();
        struct epoll_event event;
        event.data.fd = fd; // 事件对应的文件描述符
        event.events = channel->Events(); // 需要监控的事件
        int ret = epoll_ctl(_epfd, op, fd, &event);
        if(ret < 0){
            LOG_ERROR("EPOLL_CTL ERROR");
        }
        return ;
    }

    // 判断一个 Channel 是否已经添加了 事件监控
    bool HasChannel(Channel* channel){
        return _channels.find(channel->Fd()) != _channels.end();
    }

public:
    Poller(){
        // _epfd = epoll_create(MAX_EPOLLEREVENTS); // 这个已经过时
        _epfd = epoll_create1(EPOLL_CLOEXEC); // 创建 epoll 文件描述符
        if(_epfd < 0){
            LOG_ERROR("EPOLL_CREATE ERROR");
            abort(); // 退出程序
        }
    }

    Poller(const Poller&) = delete;
    Poller& operator=(const Poller&) = delete;

    // 添加 / 修改 监控事件
    void UpdateEvent(Channel* channel){
        bool ret = HasChannel(channel);
        if(!ret){
            // 不存在, 添加事件
            _channels.insert(std::make_pair(channel->Fd(), channel)); // 添加到映射表
            return Update(channel, EPOLL_CTL_ADD); 
        }
        return Update(channel, EPOLL_CTL_MOD); // 已经存在, 修改事件
    }

    void RemoveEvent(Channel* channel){
        auto it = _channels.find(channel->Fd());
        if(it != _channels.end()){
            _channels.erase(it); // 从映射表中删除
        }
        Update(channel, EPOLL_CTL_DEL); // 删除事件
    }

    // 开始监控, 返回活跃连接
    void Poll(std::vector<Channel*> *active){
        // int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
        int nfds = epoll_wait(_epfd, _events, MAX_EPOLLEREVENTS, -1);
        if(nfds < 0){
            if(errno == EINTR){
                return; // 被信号中断
            }
            LOG_ERROR("EPOLL_WAIT ERROR: %s\n", strerror(errno));
            abort(); // 退出程序
        }
        // 遍历活跃连接
        for(int i = 0; i < nfds; ++i){ 
            int fd = _events[i].data.fd;
            auto it = _channels.find(fd);
            assert(it != _channels.end()); // 断言: 事件一定存在

            Channel* channel = it->second;
            channel->SetREvents(_events[i].events); // 设置当前事件
            active->push_back(channel); // 添加到活跃连接列表
        }
    }

private:
    int _epfd; // epoll 文件描述符
    struct epoll_event _events[MAX_EPOLLEREVENTS]; // epoll 事件数组
    std::unordered_map<int, Channel*> _channels; // fd -> Channel 映射表
};